﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace X23.Util.TreeUtil
{
    public static class TreeUtil
    {

        #region 递归树
        public static List<TreeDto<T>> ListToTreeByRecursion<T, K>(this List<T> all, Func<T, K> idFunc, Func<T, K> pidFunc, object firstVal) where K : notnull
        {
            var target = all.Where(x => Equals(pidFunc(x), firstVal)).Select(x => new TreeDto<T> { Data = x }).ToList();
            var list = all.Select(x => new TreeDto<T> { Data = x }).ToList();
            return ListToTree(target, list, idFunc, pidFunc);
        }
        private static List<TreeDto<T>> ListToTree<T, K>(List<TreeDto<T>> target, List<TreeDto<T>> list, Func<T, K> idFunc, Func<T, K> pidFunc)
        {
            target.ForEach(item =>
            {
                var children = list.Where(x => Equals(pidFunc(x.Data), idFunc(item.Data))).ToList();
                if (children.Count > 0)
                {
                    ListToTree(children, list, idFunc, pidFunc);
                }
                item.Children = children;
            });
            return target;
        }
        #endregion


        public static List<TreeDto<T>> ListToTreeByDic<T, K>(this List<T> source, Func<T, K> idFunc, Func<T, K> pidFunc, object firstVal) where K : notnull
        {
            var tempDic = source.ToDictionary(key => idFunc(key), val => new TreeDto<T> { Data = val });
            var result = new List<TreeDto<T>>();

            foreach (var item in tempDic)
            {
                var pid = pidFunc(item.Value.Data);
                var isRoot = Equals(pid, firstVal);
                if (!isRoot)
                {
                    var isContainsKey = tempDic.ContainsKey(pid);
                    if (!isContainsKey)
                    {
                        throw new Exception($"{pid}节点不存在！");
                    }
                    tempDic[pid].Children.Add(item.Value);
                }
                else
                {
                    result.Add(item.Value);
                }
            }
            return result;
        }
    }

    public class TreeDto<T>
    {
        public T Data { get; set; }
        public List<TreeDto<T>> Children { get; set; } = new List<TreeDto<T>>();
    }
}
